package JDBC;
import GenerateDB.Columna;
import GenerateDB.Externa;
import GenerateDB.Tabla;
import Models.Model;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;


/**
 *
 * @author masterinftel11
 */
public class UtilsJDBC {
    
    private Connection con = null;
    private final static String cadConexion = "jdbc:oracle:thin:@olimpia.lcc.uma.es:1521:edgar";
    private final static String userName = "inftel13_23";
    private final static String pwd = "trella";
    /**
     * Constructor that opens the connection with the database.
     */
    public UtilsJDBC() {
        try {
            
            Class.forName("oracle.jdbc.driver.OracleDriver");
            
        } catch (ClassNotFoundException e) {
            
            System.out.println("Where is your Oracle JDBC Driver?");
            System.out.println(e);
            return;
            
        }
        
        //System.out.println("Oracle JDBC Driver Registered!");
        
        con = null;
        
        try {
            con = DriverManager.getConnection(
                    cadConexion, userName,
                    pwd);
            con.setAutoCommit(false);
        } catch (SQLException e) {
            
            System.out.println("Connection Failed! Check output console");
            System.out.println(e);
            return;
            
        }
        if (con == null)
            System.out.println("Failed to make connection!");
        //else
        //    System.out.println("Connected!");
    }
    
    /**
     * 
     * @return 
     */
    public HashMap<String,ArrayList<String> > getKeys(){
        return null;
        
    }
    
    /**
     * Muestra el último modelo
     * @return created models
     */
    public Model getLastModel(){
        Model lastmodel = null;
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("select * from (Select * from esquema order by fecha_creacion desc) where rownum=1")) {
                ResultSet rows = smt.executeQuery();
                while(rows.next()){
                    lastmodel = new Model(rows.getString("nombre"), rows.getDate("fecha_creacion").toString());
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }
        return lastmodel;
    }    
    
    
    /**
     * Method to get Models
     * @return created models
     */
    public ArrayList<Model> getModels(){
        ArrayList<Model> models = new ArrayList<>();
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("select * from esquema")) {
                ResultSet rows = smt.executeQuery();
                while(rows.next()){
                    models.add(new Model(rows.getString("nombre"), rows.getDate("fecha_creacion").toString()));
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }
        return models;
    }
    

    
    /**
     * Inserta una tupla
     * @param update to do
     */
    public void insert(String update){//Falta comprobar errores
        try {
            try (PreparedStatement smt = con.prepareStatement(update)) {
                smt.executeUpdate();
            }//Faltaria el catch......
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }
    }    
    
    /**
     * Inserta una tupla
     * @param update to do
     */
    public void delete(String esquema){//Falta comprobar errores

    }     

    
    /*************************** SELECT ***************************
    /**
     * Saca las claves candidatas por cada entidad
     * @param esquema
     * @return 
     */
    public HashMap<String, ArrayList<String> >  getEntityKeys(String esquema) {
        HashMap<String, ArrayList<String> > posibleskeys = new HashMap<>();
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("Select dato_ent, atributo from ATRIBUTOS where nombre_ent IS NOT NULL and ATRIBUTO_COM IS NULL and nombre=?")) {
                smt.setString(1, esquema);

                ResultSet rows = smt.executeQuery();
                String nuevaentidad = "";
                while(rows.next()){
                    String entidad = rows.getString("dato_ent");
                    String atributo = rows.getString("atributo");
                    if(entidad == null ? nuevaentidad != null : !entidad.equals(nuevaentidad)){
                        nuevaentidad = entidad;
                        ArrayList<String> atributos = new ArrayList<>();
                        posibleskeys.put(entidad, atributos);
                        posibleskeys.get(entidad).add(rows.getString("atributo"));
                    }
                    else{
                        posibleskeys.get(entidad).add(rows.getString("atributo"));
                    }
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }    
        return posibleskeys;
    }
    
    /**
     * Si la entidad del padre de atributo_com se encuentra en primarias
     * @param primarias
     * @param esquema
     * @param atributo_com
     * @return 
     */
    public String entidadatributo_com(HashMap<String, String > primarias, String esquema, String atributo_com){
        String entidad = null;
        try {//Se convierte en 2 try porque no quiere el smt.close
            //Falta: Select atributo_com, dato_ent, atributo from ATRIBUTOS where (nombre_ent IS NOT NULL OR (nombre_ent IS NULL and NOMBRE_COM IS NOT NULL and ATRIBUTO_COM IN(Select ATRIBUTO from ATRIBUTOS where ATRIBUTO IS NOT NULL and nombre_com='Patronato1'))) and TIPO != 'COMPUESTO' and nombre='Patronato1';

            try (PreparedStatement smt = con.prepareStatement("Select dato_ent from ATRIBUTOS where atributo=? and nombre=?")) {
                smt.setString(1, atributo_com);
                smt.setString(2, esquema);
                ResultSet rows = smt.executeQuery();
                while(rows.next()){
                    entidad = rows.getString("dato_ent");
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }         
        
        
        
        return entidad;
    }
    
    /******** SELECT ***********/
    /**
     * Saca las claves primerias elegidas (con atributo compuesto)
     * @param esquema
     * @param primarias
     * @return 
     */
    public HashMap<String, ArrayList<String> >  getEntityPrimariKeys(String esquema, HashMap<String, String > primarias) {
        HashMap<String, ArrayList<String> > posibleskeys = new HashMap<>();
        try {//Se convierte en 2 try porque no quiere el smt.close

            try (PreparedStatement smt = con.prepareStatement("Select atributo_com, dato_ent, atributo from ATRIBUTOS where (nombre_ent IS NOT NULL OR (nombre_ent IS NULL and ATRIBUTO_COM IS NOT NULL and ATRIBUTO_COM IN (Select atributo from ATRIBUTOS where nombre_ent IS NOT NULL and nombre=?))) and TIPO != 'COMPUESTO' and nombre=?")) {
                smt.setString(1, esquema);
                smt.setString(2, esquema);
                ResultSet rows = smt.executeQuery();
                String nuevaentidad = "";
                while(rows.next()){
                    String atributo_com = rows.getString("atributo_com");
                    String entidad = rows.getString("dato_ent");
                    String atributo = rows.getString("atributo");
                    if(((primarias.containsKey(entidad)) && ((primarias.get(entidad) == null ? atributo_com == null : primarias.get(entidad).equals(atributo_com)) || (primarias.get(entidad) == null ? atributo == null : primarias.get(entidad).equals(atributo)))) || entidad == null){
                        if(entidad == null)//Cuando es atributo compuesto, los atributos "hijos" no referencian a la entidad, por eso tiene que cojer el padre...
                           entidad = entidadatributo_com(primarias,esquema,atributo_com);
                        if(entidad != null){
                            if(entidad == null ? nuevaentidad != null : !entidad.equals(nuevaentidad)) {//si entidad y nuevaentidad son distintos
                                nuevaentidad = entidad;
                                ArrayList<String> atributos = new ArrayList<>();
                                posibleskeys.put(entidad, atributos);
                                posibleskeys.get(entidad).add(atributo);
                            }
                            else{
                                posibleskeys.get(entidad).add(atributo);
                            }  
                        }
                    }
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }    
        return posibleskeys;
    }    
    
    /**
     * Devuelve las tablas de TENTIDAD
     * @param esquema
     * @param datoentidad
     * @return 
     */
    public ArrayList<Tabla> getEntitys(String esquema){
        ArrayList<Tabla> tablas = new ArrayList<>();
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("Select * from ATRIBUTOS where TIPO != 'COMPUESTO' and nombre=? and dato IN(Select dato from TENTIDAD where nombre=?)")) {
                smt.setString(1, esquema);
                smt.setString(2, esquema);
                
                ResultSet rows = smt.executeQuery();
                int numtabla = 0;
                
                String nuevodato = "";
                while(rows.next()){
                    String dato = rows.getString("dato");
                    String atributo = rows.getString("atributo");
                    int multivaluado = rows.getInt("multivaluado");
                    int derivado = rows.getInt("derivado");
                    String tipo = rows.getString("tipo");
                    int prec = rows.getInt("prec");
                    int escala = rows.getInt("escala");
                    int notnull = rows.getInt("notnull");
                    
                    if(nuevodato == null ? dato != null : !nuevodato.equals(dato)){//Inserta tabla
                        nuevodato = dato;
                        tablas.add(new Tabla(dato));
                        tablas.get(numtabla).addColumna(new Columna(atributo,multivaluado,derivado,tipo,prec,escala,notnull));
                        numtabla++;
                    }
                    else{
                        tablas.get(numtabla-1).addColumna(new Columna(atributo,multivaluado,derivado,tipo,prec,escala,notnull));
                    }
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }    
        
        
        return tablas;
    }
    
    /**
     * Si una entidada debil depende de una fuerte
     * @param esquema
     * @param entdebil
     * @return 
     */
    private boolean isParcial(String esquema, String entdebil,String atributo){
        boolean isparcial = false;
        
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("Select * from TENTDEBIL where nombre=? and datoatrib_par=? and (atributo_par = ? or atributo_par IN(Select atributo_com from ATRIBUTOS where nombre=? and dato=? and atributo=?))")) {
                smt.setString(1, esquema);
                smt.setString(2, entdebil);
                smt.setString(3, atributo);
                smt.setString(4, esquema);
                smt.setString(5, entdebil);
                smt.setString(6, atributo);
                ResultSet rows = smt.executeQuery();
                while(rows.next()){
                    isparcial = true;
                }
            }
            
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }         
        return isparcial;
    }
    
    /**
     * Devuelve las tablas de TENTIDAD
     * @param esquema
     * @param clavesprimarias
     * @return 
     */
    public ArrayList<Tabla> getWeakEntitys(String esquema, HashMap<String, ArrayList<String> > clavesprimarias){
        ArrayList<Tabla> tablas = new ArrayList<>();
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("Select at.nombre, at.dato, at.atributo, at.multivaluado, at.derivado, at.tipo, at.prec, at.escala, at.notnull from ATRIBUTOS at where at.TIPO != 'COMPUESTO' and at.nombre=? and at.dato IN(Select datoatrib_par from TENTDEBIL where nombre=?)")) {
                smt.setString(1, esquema);
                smt.setString(2, esquema);
                
                ResultSet rows = smt.executeQuery();
                int numtabla = 0;
                
                String nuevodato = "";
                while(rows.next()){
                    String dato = rows.getString("dato");
                    String atributo = rows.getString("atributo");
                    int multivaluado = rows.getInt("multivaluado");
                    int derivado = rows.getInt("derivado");
                    String tipo = rows.getString("tipo");
                    int prec = rows.getInt("prec");
                    int escala = rows.getInt("escala");
                    int notnull = rows.getInt("notnull");
                    
                    if(nuevodato == null ? dato != null : !nuevodato.equals(dato)){//Inserta tabla nueva
                        nuevodato = dato;
                        tablas.add(new Tabla(dato));
                        tablas.get(numtabla).addColumna(new Columna(atributo,multivaluado,derivado,tipo,prec,escala,notnull));
                        numtabla++;
                    }
                    else{
                        tablas.get(numtabla-1).addColumna(new Columna(atributo,multivaluado,derivado,tipo,prec,escala,notnull));
                    }
                    
                    if(isParcial(esquema,dato,atributo)){//Si el atributo es parcial se añade a la tabla como clave primaria
                        tablas.get(tablas.size()-1).addPK(atributo);                        
                    }
                        
                }
            }
            
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }    
        
        
        return tablas;
    }    
    
    /**
     * Nos da información de un atributo de un esquema, entidad y atributo
     * @param esquema
     * @param entidad
     * @param atr
     * @return 
     */
    private Columna PKEntity(String esquema, String entidad, String atr){
        Columna c = null;
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("Select * from ATRIBUTOS where nombre=? and dato=? and atributo=?")) {
                smt.setString(1, esquema);
                smt.setString(2, entidad);
                smt.setString(3, atr);
                
                ResultSet rows = smt.executeQuery();

                while(rows.next()){
                    String atributo = rows.getString("atributo");
                    int multivaluado = rows.getInt("multivaluado");
                    int derivado = rows.getInt("derivado");
                    String tipo = rows.getString("tipo");
                    int prec = rows.getInt("prec");
                    int escala = rows.getInt("escala");
                    int notnull = rows.getInt("notnull");
                    c=new Columna(atributo, multivaluado, derivado, tipo, prec, escala, notnull);
                }
            }
            
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }        
        return c;
    }
    
    /**
     * Poner las claves primarias a las tablas de entidades débiles
     * @param esquema
     * @param clavesprimarias 
     * @param tablas 
     */
    public void addColumnsPKtoWE(String esquema, HashMap<String, ArrayList<String> > clavesprimarias,ArrayList<ArrayList<Tabla> > tablas){
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("Select dato,datoatrib_par from TENTDEBIL where dato IN (Select dato from TENTIDAD where nombre=?) and nombre=?")) {
                smt.setString(1, esquema);
                smt.setString(2, esquema);
                
                ResultSet rows = smt.executeQuery();

                while(rows.next()){
                    String dato = rows.getString("dato");
                    String datoatrib_par = rows.getString("datoatrib_par");
                    
                    boolean encontrado = false;
                    if(clavesprimarias.containsKey(dato)){//Si depende directamente de clave primaria
                        int i=0;
                        while(!encontrado){
                            if(tablas.get(1).get(i).getNombre() == null ? datoatrib_par == null : tablas.get(1).get(i).getNombre().equals(datoatrib_par)){
                                for(int j=0; j<clavesprimarias.get(dato).size(); j++){
                                    tablas.get(1).get(i).addPK(clavesprimarias.get(dato).get(j));
                                    tablas.get(1).get(i).addColumna(PKEntity(esquema, dato, clavesprimarias.get(dato).get(j)));
                                }
                                tablas.get(1).get(i).addFK(new Externa(clavesprimarias.get(dato), dato,"")); //Clave externa
                                encontrado = true;
                            }
                            i++;
                        }
                    }
                }
            }
            
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }  
    }

    
    /**
     * Poner las claves primarias a las tablas de entidades débiles
     * @param esquema
     * @param tablas 
     */
    public void addColumnsPKtoWE(String esquema,ArrayList<ArrayList<Tabla> > tablas){
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("Select dato as proviene, datoatrib_par as entidaddebil from TENTDEBIL where dato NOT IN (Select dato from TENTIDAD where nombre=?) and nombre=?")) {
                smt.setString(1, esquema);
                smt.setString(2, esquema);
                
                ResultSet rows = smt.executeQuery();

                HashMap<String,String> debiles = new HashMap<>();
                while(rows.next()){
                    String proviene = rows.getString("proviene");
                    String entidaddebil = rows.getString("entidaddebil");
                    debiles.put(proviene, entidaddebil);
                }
                
                for(int i=0; i<tablas.get(1).size(); i++){//Recorre
                    if(!tablas.get(1).get(i).getPK().isEmpty() && debiles.get(tablas.get(1).get(i).getNombre()) != null){//Si ya tiene definida la primaria y proviene                            
                        for(int j=0; j<tablas.get(1).size(); j++){//Recorre para buscar la debil
                            if(tablas.get(1).get(j).getNombre() == null ? debiles.get(tablas.get(1).get(i).getNombre()) == null : tablas.get(1).get(j).getNombre().equals(debiles.get(tablas.get(1).get(i).getNombre()))){//la encuentra
                                for(int k=0; k<tablas.get(1).get(i).getPK().size(); k++){
                                    tablas.get(1).get(j).addPK(tablas.get(1).get(i).getPK().get(k));
                                }
                                tablas.get(1).get(j).addColumnas(tablas.get(1).get(i).getColumnasPK());
                                tablas.get(1).get(j).addFK(new Externa(tablas.get(1).get(i).getPK(), tablas.get(1).get(i).getNombre(),"")); //Clave externa
                            }
                        }   
                    }
                }
                    
            }
            
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }  
    }    
    
    /**
     * Índice donde se encuentra una entidad
     * @param entitys
     * @param entity
     * @return 
     */
    private int findEntity(ArrayList<Tabla> entitys, String entity){
        int pos = -1;
        for(int i=0; i<entitys.size(); i++){
            if(entitys.get(i).getNombre() == null ? entity == null : entitys.get(i).getNombre().equals(entity))
                pos = i;
        }
        return pos;
    }
    
    
   /**
    * Asigna el atributo en una relación
    * @param esquema
    * @param relacion
    * @param tablas
    * @param entidad
    * @param tipoentidad 
    */
    private void setAtribRel(String esquema, String relacion, ArrayList<ArrayList<Tabla> > tablas, int entidad, int tipoentidad){
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("Select * from ATRIBUTOS where nombre=? and dato=?")) {
                smt.setString(1, esquema);
                smt.setString(2, relacion);
                
                ResultSet rows = smt.executeQuery();

                while(rows.next()){
                    String atributo = rows.getString("atributo");
                    int multivaluado = rows.getInt("multivaluado");
                    int derivado = rows.getInt("derivado");
                    String tipo = rows.getString("tipo");
                    int prec = rows.getInt("prec");
                    int escala = rows.getInt("escala");
                    int notnull = rows.getInt("notnull");
                    
                    tablas.get(tipoentidad).get(entidad).addColumna(new Columna(atributo, multivaluado, derivado, tipo, prec, escala, notnull));
                }
            }
            
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        } 
    }
    
    /**
     * Asigna el atributo en una relación NN
     * @param esquema
     * @param relacion
     * @param t 
     */
    private void setAtribRelnn(String esquema, String relacion, Tabla t){
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("Select * from ATRIBUTOS where nombre=? and dato=?")) {
                smt.setString(1, esquema);
                smt.setString(2, relacion);
                
                ResultSet rows = smt.executeQuery();

                while(rows.next()){
                    String atributo = rows.getString("atributo");
                    int multivaluado = rows.getInt("multivaluado");
                    int derivado = rows.getInt("derivado");
                    String tipo = rows.getString("tipo");
                    int prec = rows.getInt("prec");
                    int escala = rows.getInt("escala");
                    int notnull = rows.getInt("notnull");
                    
                    t.addColumna(new Columna(atributo, multivaluado, derivado, tipo, prec, escala, notnull));
                }
            }
            
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        } 
    }    
    /**
     * Gestiona las relaciones
     * @param esquema
     * @param relacion 
     */
    private Tabla addColumnRel(String esquema, String relacion,ArrayList<ArrayList<Tabla> > tablas, HashMap<String, ArrayList<String> > clavesprimarias){
        Tabla nn = null;
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("Select datoentidad, nomrol, minimo, maximo from PAPEL where nombreentidad=? and datorelacion=?")) {
                smt.setString(1, esquema);
                smt.setString(2, relacion);
                ResultSet rows = smt.executeQuery();
                
                ArrayList<String> entidades = new ArrayList<>();
                ArrayList<String> minimos = new ArrayList<>();
                ArrayList<String> maximos = new ArrayList<>();
                ArrayList<String> nomrols = new ArrayList<>();
                while(rows.next()){
                   entidades.add(rows.getString("datoentidad"));
                   minimos.add(rows.getString("minimo"));
                   maximos.add(rows.getString("maximo"));
                   nomrols.add(rows.getString("nomrol"));
                }
                /** Distintas situaciones **/
                //Buscar entidades de las tablas ya creadas
                int ent1 = findEntity(tablas.get(0), entidades.get(0)), ent2, tipoentidad=0;
                if(ent1 == -1){//La relacion es debil
                    ent1 = findEntity(tablas.get(1), entidades.get(1));
                    ent2 = findEntity(tablas.get(1), entidades.get(1));
                    tipoentidad=1;
                }
                else{
                    ent2 = findEntity(tablas.get(0), entidades.get(1));
                } 
                
                
                //PASO 3 --> R binaria 1:1
                if(("1".equals(minimos.get(0)) || "1".equals(maximos.get(0))) && ("1".equals(minimos.get(1)) || "1".equals(maximos.get(1)))){
                    for(int i=0; i<tablas.get(tipoentidad).get(ent1).getPK().size();i++){
                        tablas.get(tipoentidad).get(ent2).addColumna(new Columna(PKEntity(esquema, tablas.get(tipoentidad).get(ent1).getNombre(),tablas.get(tipoentidad).get(ent1).getPK().get(i))));
                        tablas.get(tipoentidad).get(ent2).addPK(tablas.get(tipoentidad).get(ent1).getPK().get(i));
                    }
                    tablas.get(tipoentidad).get(ent1).addFK(new Externa(tablas.get(tipoentidad).get(ent2).getPK(), tablas.get(tipoentidad).get(ent1).getNombre(),""));
                    setAtribRel(esquema, relacion, tablas, ent1, tipoentidad);//Añade los atributos propios de la entidad
                }

                //PASO 4  --> R binaria 1:N
                else if((("1".equals(minimos.get(0)) && "1".equals(maximos.get(0)))) || (("1".equals(minimos.get(1)) && "1".equals(maximos.get(1))))){
                    if(("1".equals(minimos.get(0)) && "1".equals(maximos.get(0)))){
                        for(int i=0; i<tablas.get(tipoentidad).get(ent2).getPK().size();i++){
                            tablas.get(tipoentidad).get(ent1).addColumna(new Columna(PKEntity(esquema, tablas.get(tipoentidad).get(ent2).getNombre(),tablas.get(tipoentidad).get(ent2).getPK().get(i))));
                            tablas.get(tipoentidad).get(ent1).addPK(tablas.get(tipoentidad).get(ent2).getPK().get(i));
                        }            
                        tablas.get(tipoentidad).get(ent1).addFK(new Externa(tablas.get(tipoentidad).get(ent2).getPK(), tablas.get(tipoentidad).get(ent1).getNombre(),""));
                        setAtribRel(esquema, relacion, tablas, ent1, tipoentidad);//Añade los atributos propios de la relacion
                    }
                    else{
                        for(int i=0; i<tablas.get(tipoentidad).get(ent1).getPK().size();i++){
                            tablas.get(tipoentidad).get(ent2).addColumna(new Columna(PKEntity(esquema, tablas.get(tipoentidad).get(ent1).getNombre(),tablas.get(tipoentidad).get(ent1).getPK().get(i))));
                            tablas.get(tipoentidad).get(ent2).addPK(tablas.get(tipoentidad).get(ent1).getPK().get(i));
                        }
                        tablas.get(tipoentidad).get(ent2).addFK(new Externa(tablas.get(tipoentidad).get(ent1).getPK(), tablas.get(tipoentidad).get(ent2).getNombre(),""));
                        setAtribRel(esquema, relacion, tablas, ent2, tipoentidad);//Añade los atributos propios de la relacion
                    }
                }

                //PASO 5   --> R binaria N:N
                else{
                    nn = new Tabla(relacion);
                    //Se añaden claves externas
                    nn.addFK(new Externa(tablas.get(tipoentidad).get(ent1).getPK(), tablas.get(tipoentidad).get(ent1).getNombre(),nomrols.get(0)));
                    nn.addFK(new Externa(tablas.get(tipoentidad).get(ent2).getPK(), tablas.get(tipoentidad).get(ent2).getNombre(),nomrols.get(1)));
                    
                    ArrayList<Columna> ColsPK = tablas.get(tipoentidad).get(ent1).getColumnasPK();
                    for(int j=0; j<ColsPK.size(); j++){
                        nn.addColumna(ColsPK.get(j));
                        nn.lastColumna().setAtributo(nn.lastColumna().getAtributo()+nomrols.get(0));
                    }

                    for(int i=0; i<tablas.get(tipoentidad).get(ent1).getPK().size(); i++){
                        nn.addPK(tablas.get(tipoentidad).get(ent1).getPK().get(i)+nomrols.get(0));
                    }
                    
                    ArrayList<Columna> ColsPK2 = tablas.get(tipoentidad).get(ent2).getColumnasPK();
                    for(int j=0; j<ColsPK2.size(); j++){
                        nn.addColumna(ColsPK2.get(j));
                        nn.lastColumna().setAtributo(nn.lastColumna().getAtributo()+nomrols.get(1));
                    }
                    for(int i=0; i<tablas.get(tipoentidad).get(ent2).getPK().size(); i++){
                        nn.addPK(tablas.get(tipoentidad).get(ent2).getPK().get(i)+nomrols.get(1));
                    }
                    
                    setAtribRelnn(esquema, relacion, nn);
                }                        
            }
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }
        return nn;
    }
    
    /**
     * Gestiona la relaciones binarias y devuelve las tablas que se crean
     * @param esquema 
     * @param tablas 
     * @return  
     */
    public ArrayList<Tabla> relbinarys(String esquema,ArrayList<ArrayList<Tabla> > tablas, HashMap<String, ArrayList<String> > clavesprimarias){
        ArrayList<Tabla> relacionesnn = new ArrayList<>();
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("Select datorelacion from PAPEL where nombreentidad=? group by datorelacion having count(*)=2")) {
                smt.setString(1, esquema);
                ResultSet rows = smt.executeQuery();
                
                while(rows.next()){
                    String relacion = rows.getString("datorelacion");
                    Tabla nn = addColumnRel(esquema, relacion,tablas,clavesprimarias);
                    if(nn != null){
                        relacionesnn.add(nn);
                    }
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }
        return relacionesnn;
    }    
    
    /**
     * Devuelve las tablas de los atributos multivaluados
     * @param esquema
     * @param clavesprimarias
     * @return 
     */
    public ArrayList<Tabla> multivaluado(String esquema, HashMap<String, ArrayList<String> > clavesprimarias){
        ArrayList<Tabla> multivaluados = new ArrayList<>();
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("Select * from ATRIBUTOS where atributo_com IN(Select atributo from ATRIBUTOS where MULTIVALUADO=1) and nombre=?")) {
                smt.setString(1, esquema);
                ResultSet rows = smt.executeQuery();
                
                while(rows.next()){
                    String atributo = rows.getString("atributo");
                    String dato = rows.getString("dato");
                    
                    Tabla n = new Tabla(atributo);
                    
                    n.addColumna(PKEntity(esquema, dato, atributo));
                    for(int i=0; i<clavesprimarias.get(dato).size();i++){
                        n.addColumna(PKEntity(esquema, dato, clavesprimarias.get(dato).get(i)));
                        n.addPK(clavesprimarias.get(dato).get(i));
                    }
                    n.addFK(new Externa(clavesprimarias.get(dato), dato, ""));
                    
                    multivaluados.add(n);
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }
        return multivaluados;
    } 
    
    
    /**************************************************************************/
    /********************** Selects para MONGO ********************************/
    /**************************************************************************/
    public ArrayList<HashMap<String,Object> > entidadesaisladas(){
        ArrayList<HashMap<String,Object> > obj = new ArrayList<>();
        
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("SELECT nombre as esquema, dato as entidad FROM TENTIDAD WHERE dato NOT IN (SELECT datoentidad FROM PAPEL GROUP BY datoentidad) AND dato NOT IN (SELECT dato FROM TENTDEBIL GROUP BY dato)")) {
                ResultSet rows = smt.executeQuery();
                
                while(rows.next()){
                    HashMap<String,Object> row = new HashMap<>();
                    String esquema = rows.getString("esquema");
                    String entidad = rows.getString("entidad");
                   
                    row.put("esquema", esquema);
                    row.put("entidad", entidad);
                    obj.add(row);
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }        
        return obj;
    }
    
    
    public ArrayList<HashMap<String,Object> > entdebilrelident(){
        ArrayList<HashMap<String,Object> > obj = new ArrayList<>();
        
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("SELECT tentdebil.nombre as esquema, tentdebil.dato as entidadfuerte, tentdebil.datoatrib_par as entidaddebil, trelident.dato as relacionidentificacion FROM TENTDEBIL, TRELIDENT WHERE TENTDEBIL.datorelident = TRELIDENT.dato")) {
                ResultSet rows = smt.executeQuery();
                
                while(rows.next()){
                    HashMap<String,Object> row = new HashMap<>();
                    String esquema = rows.getString("esquema");
                    String entidadfuerte = rows.getString("entidadfuerte");
                    String entidaddebil = rows.getString("entidaddebil");
                    String relacionidentificacion = rows.getString("relacionidentificacion");
                    
                    
                    row.put("esquema", esquema);
                    row.put("entidadfuerte", entidadfuerte);
                    row.put("entidaddebil", entidaddebil);
                    row.put("relacionidentificacion", relacionidentificacion);
                    
                    obj.add(row);
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }        
        return obj;
    }
    
    public ArrayList<HashMap<String,Object> > reflexivas(){
        ArrayList<HashMap<String,Object> > obj = new ArrayList<>();
        
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("SELECT DISTINCT p1.nombrerelacion as esquema,p1.datoentidad as entidad, p1.datorelacion as relacion FROM PAPEL p1, PAPEL p2 WHERE p1.nombrerelacion = p2.nombrerelacion AND p1.datorelacion = p2.datorelacion AND p1.datoentidad = p2.datoentidad AND p1.nomrol <> p2.nomrol")) {
                ResultSet rows = smt.executeQuery();
                
                while(rows.next()){
                    HashMap<String,Object> row = new HashMap<>();
                    String esquema = rows.getString("esquema");
                    String entidad = rows.getString("entidad");
                    String relacion = rows.getString("relacion");
                    
                    
                    row.put("esquema", esquema);
                    row.put("entidad", entidad);
                    row.put("relacion", relacion);
                    
                    obj.add(row);
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }        
        return obj;
    }    
    
    public ArrayList<HashMap<String,Object> > ternarias(){
        ArrayList<HashMap<String,Object> > obj = new ArrayList<>();
        
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("SELECT nombrerelacion as esquema, datorelacion as relacion, COUNT (*) AS grado FROM PAPEL GROUP BY nombrerelacion,datorelacion")) {
                ResultSet rows = smt.executeQuery();
                
                while(rows.next()){
                    HashMap<String,Object> row = new HashMap<>();
                    String esquema = rows.getString("esquema");
                    String relacion = rows.getString("relacion");
                    int grado = rows.getInt("grado");
                    
                    
                    row.put("esquema", esquema);
                    row.put("relacion", relacion);
                    row.put("grado", grado);
                    
                    obj.add(row);
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }        
        return obj;
    }   
    
    
    public ArrayList<HashMap<String,Object> > entidadpornumrel(){
        ArrayList<HashMap<String,Object> > obj = new ArrayList<>();
        
        try {//Se convierte en 2 try porque no quiere el smt.close
            try (PreparedStatement smt = con.prepareStatement("SELECT nombreentidad as esquema,datoentidad as entidad, count(*) as numentidades FROM papel GROUP BY datoentidad,nombreentidad")) {
                ResultSet rows = smt.executeQuery();
                
                while(rows.next()){
                    HashMap<String,Object> row = new HashMap<>();
                    String esquema = rows.getString("esquema");
                    String entidad = rows.getString("entidad");
                    int numentidades = rows.getInt("numentidades");
                    
                    
                    row.put("esquema", esquema);
                    row.put("entidad", entidad);
                    row.put("numentidades", numentidades);
                    
                    obj.add(row);
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }        
        return obj;
    }     
    
    /**************************************************************************/
    /**
     * Method to disconnect of DataBase
     */
    public void disconnect(){
        try {
            this.con.close();
        } catch (SQLException ex) {
            Logger.getLogger(UtilsJDBC.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
